package com.sunday.common.statemachine.study.e12_Using_Extended_State;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.listener.StateMachineListener;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;

/**
 * 使用扩展状态
 * 假设您需要创建一个状态机来跟踪 很多时候，用户按下键盘上的某个键，然后终止 当按键被按下 1000 次时。一个可能但非常幼稚的解决方案 将是每按 1000 次按键创建一个新状态。 您可能会突然出现一个天文数字 状态，这自然不是很实用。
 * <p>
 * 这就是扩展状态变量通过不需要 以添加更多状态来驱动状态机更改。相反 您可以在过渡期间执行简单的变量更改。
 * <p>
 * StateMachine有一个名为 .它返回一个 名为 的接口，该接口提供对扩展状态的访问 变量。您可以通过状态机直接访问这些变量，也可以在操作或转换的回调期间访问这些变量。 以下示例显示了如何执行此操作：getExtendedState()ExtendedStateStateContext
 */

@Slf4j
@Configuration  // 声明该类为Spring的配置类
@EnableStateMachine  // 启用Spring状态机功能
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {

    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config) throws Exception {
        config
                .withConfiguration()
                .autoStartup(true)
                .listener(extendedStateVariableListener());
    }

    @Override
    public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception {
        states
                .withStates()
                .initial(OrderStates.S1)
                .fork(OrderStates.S2)
                .state(OrderStates.S3)
                .join(OrderStates.S4)
                .state(OrderStates.S5)
                .and()

                .withStates()
                .parent(OrderStates.S3)
                .initial(OrderStates.S2I)
                .state(OrderStates.S21)
                .state(OrderStates.S22)
                .end(OrderStates.S2F)
                .and()

                .withStates()
                .parent(OrderStates.S3)
                .initial(OrderStates.S3I)
                .state(OrderStates.S31)
                .state(OrderStates.S32)
                .end(OrderStates.S3F)
        ;

    }

    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
        transitions
                // 新建订单 -> 检查库存 触发条件 检查库存事件
                .withExternal()  // 配置外部状态转换（即不同状态之间的转换）
                .source(OrderStates.S1)
                .target(OrderStates.S2)
                .event(OrderEvents.TS2)
                .action(context -> {
                    log.info("TS2 : {}", context.getStateMachine().getState().getId());
                })
                .and()

                .withFork()
                .source(OrderStates.S2)
                .target(OrderStates.S21)
                .target(OrderStates.S31)
                .and()

                .withExternal()  // 配置外部状态转换（即不同状态之间的转换）
                .source(OrderStates.S21)
                .target(OrderStates.S22)
                .event(OrderEvents.TS22)
                .action(context -> {
                    context.getExtendedState().getVariables().put("test", "test value");

                    log.info("TS22 triggered, transitioning from {} to {}", context.getSource().getId(), context.getTarget().getId());
                })
                .and()

                .withExternal()  // 配置外部状态转换（即不同状态之间的转换）
                .source(OrderStates.S31)
                .target(OrderStates.S32)
                .event(OrderEvents.TS32)
                .action(context -> {
                    log.info("TS32 triggered, transitioning from {} to {}", context.getSource().getId(), context.getTarget().getId());
                })
                .and()

                .withExternal()  // 配置外部状态转换（即不同状态之间的转换）
                .source(OrderStates.S22)
                .target(OrderStates.S2F)
                .event(OrderEvents.TS2F)
                .action(context -> {
                    log.info("TS2F triggered, transitioning from {} to {}", context.getSource().getId(), context.getTarget().getId());
                })
                .and()

                .withExternal()  // 配置外部状态转换（即不同状态之间的转换）
                .source(OrderStates.S32)
                .target(OrderStates.S3F)
                .event(OrderEvents.TS3F)
                .action(context -> {
                    log.info("TS3F triggered, transitioning from {} to {}", context.getSource().getId(), context.getTarget().getId());
                })
                .and()

                // 多个源状态汇聚到 S4（通过 join）
                .withJoin()
                .source(OrderStates.S2F)
                .source(OrderStates.S3F)
                .target(OrderStates.S4)
                .and()

                // 从 S4 到 S5 的普通状态转换，带 Guard 表达式
                .withExternal()
                .source(OrderStates.S4)
                .target(OrderStates.S5)
                .guard(context -> {
                    context.getExtendedState();
                    return true;
                })
//                .guardExpression("!extendedState.variables.isEmpty()")  // 只有 extendedState 中有数据时才转移
//                .guardExpression("true")
                .action(context -> {
                    log.info("Transitioning from {} to {} based on guard expression", context.getSource().getId(), context.getTarget().getId());
                })
//                .and()

                // 当 extendedState 为空时，跳到终态
//                .withExternal()
//                .source(OrderStates.S4)
//                .target(OrderStates.SF)
////                .guardExpression("extendedState.variables.isEmpty()") // extendedState 为空时转移到终态
//                .action(context -> {
//                    log.info("Transitioning from {} to {} based on guard expression", context.getSource().getId(), context.getTarget().getId());
//                });
        ;

    }

    @Bean
    public StateMachineListener<OrderStates, OrderEvents> listener() {
        return new StateMachineListenerAdapter<>() {
            @Override
            public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {
                log.info("State change from {} to {}", from == null ? "无" : from.getId(), to.getId());
            }
        };
    }

    @Bean
    public StateMachineListenerAdapter<OrderStates, OrderEvents> extendedStateVariableListener() {
        return new ExtendedStateVariableListener();
    }

}